home *** CD-ROM | disk | FTP | other *** search
/ The CICA Windows Explosion! / The CICA Windows Explosion! - Disc 2.iso / nt / emacssrc.zip / EMACSSRC.TAR / emacs-19.17 / lib-src / rcs2log < prev    next >
Text File  |  1993-11-16  |  10KB  |  382 lines

  1. #!/bin/sh
  2.  
  3. # RCS to ChangeLog generator
  4.  
  5. # Generate a change log prefix from RCS/* and the existing ChangeLog (if any).
  6. # Output the new prefix to standard output.
  7. # You can edit this prefix by hand, and then prepend it to ChangeLog.
  8.  
  9. # Ignore log entries that start with `#'.
  10. # Clump together log entries that start with `{topic} ',
  11. # where `topic' contains neither white space nor `}'.
  12.  
  13. # Author: Paul Eggert <eggert@twinsun.com>
  14.  
  15. # $Id: rcs2log,v 1.12 1993/05/29 06:22:48 rms Exp $
  16.  
  17. # Copyright 1992, 1993 Free Software Foundation, Inc.
  18.  
  19. # This program is free software; you can redistribute it and/or modify
  20. # it under the terms of the GNU General Public License as published by
  21. # the Free Software Foundation; either version 2, or (at your option)
  22. # any later version.
  23. # This program is distributed in the hope that it will be useful,
  24. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  25. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  26. # GNU General Public License for more details.
  27. # You should have received a copy of the GNU General Public License
  28. # along with this program; see the file COPYING.  If not, write to
  29. # the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  30.  
  31. nl='
  32. '
  33.  
  34. # Parse options.
  35.  
  36. # defaults
  37. indent=8 # indent of log line
  38. length=79 # suggested max width of log line
  39. tabwidth=8 # width of horizontal tab
  40.  
  41. while :
  42. do
  43.     case $1 in
  44.     -i)    indent=${2?};;
  45.     -l)    length=${2?};;
  46.     -t)    tabwidth=${2?};;
  47.     -*)    echo >&2 "$0: usage: $0 [-i indent] [-l length] [-t tabwidth] [file ...]"
  48.         exit 1;;
  49.     *)    break
  50.     esac
  51.     shift; shift
  52. done
  53.  
  54. month_data='
  55.     m[0]="Jan"; m[1]="Feb"; m[2]="Mar"
  56.     m[3]="Apr"; m[4]="May"; m[5]="Jun"
  57.     m[6]="Jul"; m[7]="Aug"; m[8]="Sep"
  58.     m[9]="Oct"; m[10]="Nov"; m[11]="Dec"
  59.  
  60.     # days in non-leap year thus far, indexed by month (0-12)
  61.     mo[0]=0; mo[1]=31; mo[2]=59; mo[3]=90
  62.     mo[4]=120; mo[5]=151; mo[6]=181; mo[7]=212
  63.     mo[8]=243; mo[9]=273; mo[10]=304; mo[11]=334
  64.     mo[12]=365
  65. '
  66.  
  67.  
  68. # Log into $rlogout the revisions checked in since the first ChangeLog entry.
  69.  
  70. date=1970
  71. if test -s ChangeLog
  72. then
  73.     # Add 1 to seconds to avoid duplicating most recent log.
  74.     e='
  75.         /^... ... [ 0-9][0-9] [ 0-9][0-9]:[0-9][0-9]:[0-9][0-9] [0-9]+ /{
  76.             '"$month_data"'
  77.             year = $5
  78.             for (i=0; i<=11; i++) if (m[i] == $2) break
  79.             dd = $3
  80.             hh = substr($0,12,2)
  81.             mm = substr($0,15,2)
  82.             ss = substr($0,18,2)
  83.             ss++
  84.             if (ss == 60) {
  85.                 ss = 0
  86.                 mm++
  87.                 if (mm == 60) {
  88.                     mm = 0
  89.                     hh++
  90.                     if (hh == 24) {
  91.                         hh = 0
  92.                         dd++
  93.                         monthdays = mo[i+1] - mo[i]
  94.                         if (i == 1 && year%4 == 0 && (year%100 != 0 || year%400 == 0)) monthdays++
  95.                         if (dd == monthdays + 1) {
  96.                             dd = 1
  97.                             i++
  98.                             if (i == 12) {
  99.                                 i = 0
  100.                                 year++
  101.                             }
  102.                         }
  103.                     }
  104.                 }
  105.             }
  106.             printf "%d/%02d/%02d %02d:%02d:%02d\n", year, i+1, dd, hh, mm, ss
  107.             exit
  108.         }
  109.     '
  110.     d=`awk "$e" <ChangeLog` || exit
  111.     case $d in
  112.     ?*) date=$d
  113.     esac
  114. fi
  115. datearg="-d>$date"
  116.  
  117. # With no arguments, examine all files under the RCS directory.
  118. case $# in
  119. 0)
  120.     files=
  121.     for file in RCS/.* RCS/*
  122.     do
  123.         case $file in
  124.         RCS/. | RCS/..) ;;
  125.         RCS/.\* | RCS/\*) test -f "$file" && files=$files$nl$file;;
  126.         *) files=$files$nl$file
  127.         esac
  128.     done
  129.     case $files in
  130.     '') exit 0
  131.     esac
  132.     oldIFS=$IFS
  133.     IFS=$nl
  134.     set $files
  135.     IFS=$oldIFS
  136. esac
  137.  
  138. rlogout=/tmp/chg$$
  139. trap exit 1 2 13 15
  140. trap 'rm -f $rlogout; exit 1' 0
  141.  
  142. rlog "$datearg" "$@" >$rlogout || exit
  143.  
  144.  
  145. # Get the full name of each author the logs mention, and set initialize_fullname
  146. # to awk code that initializes the `fullname' awk associative array.
  147. # Warning: foreign authors (i.e. not known in the passwd file) are mishandled;
  148. # you have to fix the resulting output by hand.
  149.  
  150. initialize_fullname=
  151. authors=`
  152.     sed -n 's|^date: *[0-9]*/[0-9][0-9]/[0-9][0-9] [0-9][0-9]:[0-9][0-9]:[0-9][0-9]; *author: *\([^; ]*\).*|\1|p' <$rlogout |
  153.     sort -u
  154. `
  155. case $authors in
  156. ?*)
  157.     initialize_author=
  158.     for author in $authors
  159.     do
  160.         initialize_author="$initialize_author
  161.             author[\"$author\"] = 1
  162.         "
  163.     done
  164.  
  165.     awkscript='
  166.         BEGIN {
  167.             alphabet = "abcdefghijklmnopqrstuvwxyz"
  168.             ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  169.             '"$initialize_author"'
  170.         }
  171.         {
  172.             if (author[$1]) {
  173.                 fullname = $5
  174.                 abbr = index(fullname, "&")
  175.                 if (abbr) {
  176.                     a = substr($1, 1, 1)
  177.                     A = a
  178.                     i = index(alphabet, a)
  179.                     if (i) A = substr(ALPHABET, i, 1)
  180.                     fullname = substr(fullname, 1, abbr-1) A substr($1, 2) substr(fullname, abbr+1)
  181.                 }
  182.                 printf "fullname[\"%s\"] = \"%s\"\n", $1, fullname
  183.                 author[$1] = 0
  184.             }
  185.         }
  186.     '
  187.  
  188.     initialize_fullname=`
  189.         (cat /etc/passwd; ypmatch $authors passwd) 2>/dev/null |
  190.         awk -F: "$awkscript"
  191.     `
  192. esac
  193.  
  194.  
  195. # Function to print a single log line.
  196. # We don't use awk functions, to stay compatible with old awk versions.
  197. # `Log' is the log message (with \n replaced by \r).
  198. # `files' contains the affected files.
  199. printlogline='{
  200.  
  201.     # Following the GNU coding standards, rewrite
  202.     #    * file: (function): comment
  203.     # to
  204.     #    * file (function): comment
  205.     if (Log ~ /^\([^)]*\): /) {
  206.         i = index(Log, ")")
  207.         files = files " " substr(Log, 1, i)
  208.         Log = substr(Log, i+3)
  209.     }
  210.  
  211.     # If "label: comment" is too long, break the line after the ":".
  212.     sep = " "
  213.     if ('"$length"' <= '"$indent"' + 1 + length(files) + index(Log, CR)) sep = "\n" indent_string
  214.  
  215.     # Print the label.
  216.     printf "%s*%s:", indent_string, files
  217.  
  218.     # Print each line of the log, transliterating \r to \n.
  219.     while ((i = index(Log, CR)) != 0) {
  220.         printf "%s%s\n", sep, substr(Log, 1, i-1)
  221.         sep = indent_string
  222.         Log = substr(Log, i+1)
  223.     }
  224. }'
  225.  
  226. hostname=`(
  227.     hostname || cat /etc/whoami || uuname -l || uname -n
  228. ) 2>/dev/null` || {
  229.     echo >&2 "$0: cannot deduce hostname"
  230.     exit 1
  231. }
  232.  
  233.  
  234. # Process the rlog output, generating ChangeLog style entries.
  235.  
  236. # First, reformat the rlog output so that each line contains one log entry.
  237. # Transliterate \n to \r so that multiline entries fit on a single line.
  238. # Discard irrelevant rlog output.
  239. awk <$rlogout '
  240.     /^Working file:/ { filename = $3 }
  241.     /^date: /, /^(-----------*|===========*)$/ {
  242.         if ($0 ~ /^branches: /) { next }
  243.         if ($0 ~ /^date: [0-9][ \/0-9:]*;/) {
  244.             time = substr($3, 1, length($3)-1)
  245.             author = substr($5, 1, length($5)-1)
  246.             printf "%s %s %s %s %c", filename, $2, time, author, 13
  247.             next
  248.         }
  249.         if ($0 ~ /^(-----------*|===========*)$/) { print ""; next }
  250.         printf "%s%c", $0, 13
  251.     }
  252. ' |
  253.  
  254. # Now each line is of the form
  255. # FILENAME YYYY/MM/DD HH:MM:SS AUTHOR \rLOG
  256. #    where \r stands for a carriage return,
  257. #    and each line of the log is terminated by \r instead of \n.
  258. # Sort the log entries, first by date+time (in reverse order),
  259. # then by author, then by log entry, and finally by file name (just in case).
  260. sort +1 -3r +3 +0 |
  261.  
  262. # Finally, reformat the sorted log entries.
  263. awk '
  264.     BEGIN {
  265.         # Some awks do not understand "\r" or "\013", so we have to
  266.         # put a carriage return directly in the file.
  267.         CR="" # <-- There is a single CR between the " chars here.
  268.  
  269.         # Initialize the fullname associative array.
  270.         '"$initialize_fullname"'
  271.  
  272.         # Initialize indent string.
  273.         indent_string = ""
  274.         i = '"$indent"'
  275.         if (0 < '"$tabwidth"')
  276.             for (;  '"$tabwidth"' <= i;  i -= '"$tabwidth"')
  277.                 indent_string = indent_string "\t"
  278.         while (1 <= i--)
  279.             indent_string = indent_string " "
  280.  
  281.         # Set up date conversion tables.
  282.         # RCS uses a nice, clean, sortable format,
  283.         # but ChangeLog wants the traditional, ugly ctime format.
  284.  
  285.         # January 1, 0 AD (Gregorian) was Saturday = 6
  286.         EPOCH_WEEKDAY = 6
  287.         # Of course, there was no 0 AD, but the algorithm works anyway.
  288.  
  289.         w[0]="Sun"; w[1]="Mon"; w[2]="Tue"; w[3]="Wed"
  290.         w[4]="Thu"; w[5]="Fri"; w[6]="Sat"
  291.  
  292.         '"$month_data"'
  293.     }
  294.  
  295.     {
  296.         newlog = substr($0, 1 + index($0, CR))
  297.  
  298.         # Ignore log entries prefixed by "#".
  299.         if (newlog ~ /^#/) { next }
  300.  
  301.         if (Log != newlog || date != $2 || author != $4) {
  302.  
  303.             # The previous log and this log differ.
  304.  
  305.             # Print the old log.
  306.             if (date != "") '"$printlogline"'
  307.  
  308.             # Logs that begin with "{clumpname} " should be grouped together,
  309.             # and the clumpname should be removed.
  310.             # Extract the new clumpname from the log header,
  311.             # and use it to decide whether to output a blank line.
  312.             newclumpname = ""
  313.             sep = "\n"
  314.             if (date == "") sep = ""
  315.             if (newlog ~ /^{[^     }]*}[     ]/) {
  316.                 i = index(newlog, "}")
  317.                 newclumpname = substr(newlog, 1, i)
  318.                 while (substr(newlog, i+1) ~ /^[     ]/) i++
  319.                 newlog = substr(newlog, i+1)
  320.                 if (clumpname == newclumpname) sep = ""
  321.             }
  322.             printf sep
  323.             clumpname = newclumpname
  324.  
  325.             # Get ready for the next log.
  326.             Log = newlog
  327.             if (files != "")
  328.                 for (i in filesknown)
  329.                     filesknown[i] = 0
  330.             files = ""
  331.         }
  332.         if (date != $2  ||  author != $4) {
  333.             # The previous date+author and this date+author differ.
  334.             # Print the new one.
  335.             date = $2
  336.             author = $4
  337.  
  338.             # Convert nice RCS date like "1992/01/03 00:03:44"
  339.             # into ugly ctime date like "Fri Jan  3 00:03:44 1992".
  340.             # Calculate day of week from Gregorian calendar.
  341.             i = index($2, "/")
  342.             year = substr($2, 1, i-1) + 0
  343.             monthday = substr($2, i+1)
  344.             i = index(monthday, "/")
  345.             month = substr(monthday, 1, i-1) + 0
  346.             day = substr(monthday, i+1) + 0
  347.             leap = 0
  348.             if (2 < month && year%4 == 0 && (year%100 != 0 || year%400 == 0)) leap = 1
  349.             days_since_Sunday_before_epoch = EPOCH_WEEKDAY + year * 365 + int((year + 3) / 4) - int((year + 99) / 100) + int((year + 399) / 400) + mo[month-1] + leap + day - 1
  350.  
  351.             # Print "date  fullname  (email address)" if the fullname is known;
  352.             # print "date  author" otherwise.
  353.             # Get the fullname from the associative array.
  354.             # The email address is just author@thishostname.
  355.             printf "%s %s %2d %s %d  ", w[days_since_Sunday_before_epoch%7], m[month-1], day, $3, year
  356.             if (fullname[author])
  357.                 printf "%s  (%s@%s)\n\n", fullname[author], author, "'"$hostname"'"
  358.             else
  359.                 printf "%s\n\n", author
  360.         }
  361.         if (! filesknown[$1]) {
  362.             filesknown[$1] = 1
  363.             if (files == "") files = " " $1
  364.             else files = files ", " $1
  365.         }
  366.     }
  367.     END {
  368.         # Print the last log.
  369.         if (date != "") {
  370.             '"$printlogline"'
  371.             printf "\n"
  372.         }
  373.     }
  374. ' &&
  375.  
  376.  
  377. # Exit successfully.
  378.  
  379. exec rm -f $rlogout
  380.